package com.polaris.live.utils.zego

import android.os.Looper
import androidx.core.os.bundleOf
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.ktx.Firebase
import com.polaris.live.common.cacha.UserManager
import com.polaris.live.common.constant.CommonConst
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.manager.withDeferred
import com.polaris.live.constant.EventConst
import com.polaris.live.manager.AppConfigManager
import com.polaris.live.utils.postEvent
import com.polaris.live.utils.zego.core.EngineHandler
import com.polaris.live.utils.zego.core.EventHandlerHelper
import com.polaris.live.utils.zego.core.GameEventHandlerHelper
import com.polaris.live.utils.zego.core.MiniGameEngineHandler
import com.polaris.live.utils.zego.core.TranslationHandler
import im.zego.realtimetranslation.ZegoRealtimeTranslation
import im.zego.zegoexpress.ZegoExpressEngine
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout

/**
 * 既构的引擎管理
 *
 * @author Created by 半仙 on 2023/9/6/006 20:57
 */
object LiveEngineManage {

    const val TAG = "--Zego"

    const val TAG_GAME = "--ZegoGame"

    /**
     * rtc引擎
     */
    private var engine: EngineHandler? = null

    /**
     * 同声传译引擎
     */
    private val translationEngine: TranslationHandler = TranslationHandler()

    /**
     * 事件回调处理
     */
    val eventHandlerHelper = EventHandlerHelper()

    /**
     * 游戏事件回调
     */
    val gameEventHandlerHelper = GameEventHandlerHelper()

    init {
        if (UserManager.isLogin()) {
            AppConfigManager.getConfig(CommonConst.Zego.zegoAppId)?.let { appId ->
                createEngine(appId.toLong())
            }
        }

        getGameEngineHandler()?.getEngine()?.setGameEngineHandler(gameEventHandlerHelper)
    }

    /**
     * 获取游戏引擎
     */
    fun getGameEngineHandler(): MiniGameEngineHandler? {
        return engine?.getGameEngineHandler()
    }

    /**
     * 连接到zego的引擎
     */
    fun createEngine(appId: Long) {
        synchronized(this) {
            if (engine == null) {
                engine = EngineHandler(appId, eventHandlerHelper, gameEventHandlerHelper)
            }

            engine?.connect(UserManager.getUserId().toString())
        }
    }

    /**
     * 销毁引擎，当退出登录时
     *
     * 实际上的行为是退出房间
     */
    fun reset() {
        engine?.disconnect()
        translationEngine.disconnect()
    }

    /**
     * 返回帮助类
     */
    fun getHandler(): EngineHandler? {
        return engine
    }

    /**
     * 获取zego的引擎
     */
    fun getEngine(): ZegoExpressEngine? {
        return engine?.getEngine()
    }

    /**
     * 获取同声传译的引擎
     */
    fun getTranslationEngine(): ZegoRealtimeTranslation {
        return translationEngine.getEngine()
    }

    /**
     * 开启或关闭音频采集
     *
     * 这个需要在异步里面开启
     */
    fun enableAudioCaptureDevice(hashId: Int, enable: Boolean) {
        check(Looper.myLooper() != Looper.getMainLooper()) {
            "Enable audio capture device is not allowed on the main thread."
        }

        engine?.enableAudioCaptureDevice(hashId, enable)
    }

    /**
     * 执行在已经登录的房间中
     *
     * @param owner 生命周期的拥有者
     * @param onSuccess 成功的回调
     * @param onFailure 失败的回调，通常是超时
     */
    suspend fun withLogin(
        owner: LifecycleOwner,
        onSuccess: () -> Unit,
        onFailure: ((Throwable) -> Unit)? = null
    ) {
        if (owner.lifecycle.currentState == Lifecycle.State.DESTROYED) {
            withContext(CoroutineScopeManager.mainDispatcher) {
                onFailure(Throwable("owner is destroyed"), onFailure)

                Firebase.analytics.postEvent(
                    EventConst.ZEGO_LOGIN_ERROR,
                    bundleOf("errorMessage" to "owner is destroyed")
                )
            }
            return
        }

        val engine = engine
        if (engine == null) {
            onFailure(Throwable("engine is null"), onFailure)

            Firebase.analytics.postEvent(
                EventConst.ZEGO_LOGIN_ERROR,
                bundleOf("errorMessage" to "engine is null")
            )

            return
        }

        if (engine.isLoginRoom()) {
            onSuccess()
        } else {
            var listener: OnWithLoginListener? = null

            try {
                withTimeout(15 * 1000L) {
                    withDeferred {
                        listener = object : OnWithLoginListener {
                            override fun onSuccess() {
                                complete(Unit)
                            }

                            override fun onFailure(t: Throwable) {
                                completeExceptionally(t)
                            }
                        }

                        listener?.also { l ->
                            engine.attachLoginLister(l)

                            withContext(CoroutineScopeManager.mainDispatcher) {
                                owner.lifecycle.addObserver(object : LifecycleEventObserver {
                                    override fun onStateChanged(
                                        source: LifecycleOwner,
                                        event: Lifecycle.Event
                                    ) {
                                        if (owner.lifecycle.currentState == Lifecycle.State.DESTROYED) {
                                            engine.detachedLoginLister(l)
                                            return
                                        }
                                    }
                                })
                            }
                        }
                    }

                    listener?.also { engine.detachedLoginLister(it) }

                    withContext(CoroutineScopeManager.mainDispatcher) {
                        onSuccess()
                    }
                }
            } catch (t: Throwable) {
                listener?.also { engine.detachedLoginLister(it) }

                onFailure(t, onFailure)

                Firebase.analytics.postEvent(
                    EventConst.ZEGO_LOGIN_ERROR, bundleOf(
                        "errorType" to "error",
                        "errorMessage" to t.message,
                        "isConnected" to engine.isConnected(),
                        "isLoginRoom" to engine.isLoginRoom()
                    )
                )
            }
        }
    }

    private suspend fun onFailure(t: Throwable, onFailure: ((Throwable) -> Unit)?) {
        if (onFailure != null) {
            withContext(CoroutineScopeManager.mainDispatcher) {
                onFailure(t)
            }
        }
    }
}

interface OnWithLoginListener {

    /**
     * 登录成功的
     */
    fun onSuccess()

    /**
     * 登录失败的
     */
    fun onFailure(t: Throwable)

}